﻿using System;
using System.Collections.Generic;
using System.Threading;

namespace _18_Observer
{
    /// <summary>
    /// 观察者模式
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            //观察者是一种行为设计模式， 允许一个对象将其状态的改变通知其他对象
            var subject = new Subject();
            var observerA = new ConcreteObserverA();
            subject.Attach(observerA);

            var observerB = new ConcreteObserverB();
            subject.Attach(observerB);

            subject.SomeBusinessLogic();
            subject.SomeBusinessLogic();
            subject.Detach(observerB);
            subject.SomeBusinessLogic();
            Console.ReadKey();
        }
    }
    public interface IObserver
    {
        void Update(ISubject subject);
    }
    public interface ISubject
    {
        void Attach(IObserver observer);
        void Detach(IObserver observer);
        void Notify();
    }
    public class Subject : ISubject
    {
        public int State { get; set; } = -0;
        public List<IObserver> _observers = new List<IObserver>();
        public void Attach(IObserver observer)
        {
            Console.WriteLine("Subject:Attached an observer");
            _observers.Add(observer);
        }

        public void Detach(IObserver observer)
        {
            _observers.Remove(observer);
            Console.WriteLine("Subject:Detached an observer");
        }

        public void Notify()
        {
            Console.WriteLine("Subject:Notifying observer...");
            foreach (var observer in _observers)
            {
                observer.Update(this);
            }
        }
        public void SomeBusinessLogic()
        {
            Console.WriteLine("\nSubject: I'm doing something important.");
            State = new Random().Next(0, 10);
            Thread.Sleep(15);
            Console.WriteLine("Subject: My state has just changed to: " + this.State);
            this.Notify();
        }
    }
    class ConcreteObserverA : IObserver
    {
        public void Update(ISubject subject)
        {
            if((subject as Subject).State < 3)
            {
                Console.WriteLine("ConcreteObserverA: Reacted to the event.");
            }
        }
    }
    class ConcreteObserverB : IObserver
    {
        public void Update(ISubject subject)
        {
            if((subject as Subject).State==0 || (subject as Subject).State >= 2)
            {
                Console.WriteLine("ConcreteObserverB: Reacted to the event.");
            }
        }
    }
}
